# Copyright (c) 2998 Prabhu Gurumurthy <pgurumur@kashyapa.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

package ConfigSSH;

require 5.004;

use Carp 'croak', 'carp';
use strict;
use warnings;
use File::Temp qw(tempfile);
use File::Copy;
use Socket;
use Net::SSH2;
use vars qw($VERSION);

$VERSION = 1.0;

sub ConfigSSH::new {
   my ($class) = @_;
   # My hash consisting of all required argument
   my $self = {
      _server => undef,
      _port => 22,
      _user => undef,
      _passwd => undef,
      _enable => undef,
      _ssh => undef,
      _error => undef,
      _channel => undef,
      _config => undef,
   };

   $self->{_ssh} = Net::SSH2->new();
   bless ($self, $class);
   return $self;
}

# Returns any error, depends on the module caller to read this error
sub ConfigSSH::error ($)
{
   my ($self) = @_;
   return $self->{_error};
}

# function name gives it off, 
sub ConfigSSH::close ($)
{
   my ($self) = @_;

   # See whether the ssh handle is opened!
   if (defined($self->{_ssh})) {
      # See whether we opened a channel, if we did close it
      if (defined($self->{_channel})) {
         $self->{_channel}->close();
      }

      # If we opened the ssh handle, close it, i.e. disconnect it
      $self->{_ssh}->disconnect();
   }
}

sub ConfigSSH::get_config_file ($)
{
   my ($self) = @_;
   return $self->{_config};
}

sub ConfigSSH::connect ($$$$$$)
{
   my (($self), $server, $port, $user, $passwd, $enable) = @_;
   my $retval = 1;

   # The script does not know how to react if any of the following is not
   # defined.
   if (defined($server)) {
      $self->{_server} = $server;
   }

   if (defined($port)) {
      $self->{_port} = $port;
   }

   if (defined($user)) {
      $self->{_user} = $user;
   }

   if (defined($passwd)) {
      $self->{_passwd} = $passwd;
   }

   if (defined($enable)) {
      $self->{_enable} = $enable;
   }

   # We do not want to over ride an existing handle with another one
   if (defined($self->{_ssh})) {
      if ($self->{_ssh}->connect($self->{_server}, $self->{_port})) {
         # If we are able to connect, yeah try authenticating
         if ($self->{_ssh}->auth_password($self->{_user}, $self->{_passwd})) {
            # Yippee, auth passed, open the channel
            $self->{_channel} = $self->{_ssh}->channel();
            $retval = 0;
         }
         $self->{_error} = sprintf("cannot authenticate to %s as %s",
            $self->{_server}, $self->{_passwd});
      }
      else {
         $self->{_error} = sprintf("cannot connect to %s on port %d",
            $self->{_server}, $self->{_passwd});
      }
   }

   return $retval;
}

sub ConfigSSH::backup ($$$$)
{
   my (($self), $config, $tftp, $sleep) = @_;
   my $retval = 1;

   if (defined($self->{_channel})) {
      if (defined($config)) {
         $retval = 0;
      }
      else {
         $self->{_error} = "cannot create target config file";
      }

      if ($retval eq 0) {
         my $buffer = undef; 
         $self->{_channel}->shell();
         $self->{_channel}->write("enable\n"); 
         if (defined($self->{_enable})) {
            $self->{_channel}->write("$self->{_enable}\n"); 
         }
         else { 
            $self->{_channel}->write("$self->{_passwd}\n"); 
         }

         my $copy_message = sprintf(
            "copy /noconfirm running-config tftp://%s/%s", $tftp, $config);
         $self->{_channel}->write("$copy_message\n");
         sleep($sleep);
         $self->{_channel}->write("exit\n");

         if (-z $self->{_config}) {
            $self->{_error} = sprintf("backup failed on for %s",
               $self->{_server});
            $retval = 1;
         }
      }
   }

   return $retval;
}

1;
